package com.np.rtmpdump2;

import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.projection.MediaProjection;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Surface;

import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * 视频编码
 */
public class VideoCodec extends Thread {

    private static final String TAG = "well";
    private MediaProjection mediaProjection;    //录屏工具类
    private MediaCodec mediaCodec;  // 硬编模块
    private ScreenLive screenLive; //传输层的引用
    private VirtualDisplay virtualDisplay; //虚拟的画布
    private long timeStamp; //每一帧编码时间
    private long startTime; //推流时间
    private boolean isLiving; //是否正在直播

    public VideoCodec(ScreenLive screenLive) {
        this.screenLive = screenLive;
    }

    public void startLive(MediaProjection mediaProjection) {
        this.mediaProjection = mediaProjection;

        try {
            //https://cloud.tencent.com/document/product/267/7969 直播分辨率选取 这里选择超清
            MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 720, 1280);
            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
            //码率
            format.setInteger(MediaFormat.KEY_BIT_RATE, 25_000);
            //帧率，比较低，短视频中帧率设置得比较高，短视频中要要求，画面清晰，此时会拉长GOP序列，I帧拉长，帧率增加，文件大小最小，比如60
            //直播要求秒开，I帧2秒以内，I帧都是很多的，通过降低码率，来减小文件大小，比如15
            format.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
            //I帧
            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);
            mediaCodec = MediaCodec.createEncoderByType("video/avc");
            // 无需预览，所以第二、三个参数传null
            mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            Surface surface = mediaCodec.createInputSurface();
            // 创建一个虚拟的展示页，展示到上面的 surface
            virtualDisplay = mediaProjection.createVirtualDisplay("screen-codec", 720, 1280, 1, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, surface, null, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
        LiveTaskManager.getInstance().execute(this);
    }

    @Override
    public void run() {
        isLiving = true;
        mediaCodec.start();
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        while (isLiving) {
            if (System.currentTimeMillis() - timeStamp >= 2000) {
                Bundle params = new Bundle();
                //请求触发I帧
                params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
                //通知dsp芯片手动触发I帧
                mediaCodec.setParameters(params);
                timeStamp = System.currentTimeMillis();
            }
            int index = mediaCodec.dequeueOutputBuffer(bufferInfo, 100000);
            if (index >= 0) {
                if (startTime == 0) {
                    //毫秒,rtmp单位ms
                    startTime = bufferInfo.presentationTimeUs / 1000;
                }
                ByteBuffer buffer = mediaCodec.getOutputBuffer(index);
                byte[] outData = new byte[bufferInfo.size];
                buffer.get(outData);
                //将编码好的数据封装成packet
                RTMPPackage rtmpPackage = new RTMPPackage(outData, (bufferInfo.presentationTimeUs / 1000) - startTime);
                //将封装好的数据放到队列中
                screenLive.addPackage(rtmpPackage);
                rtmpPackage.setType(RTMPPackage.RTMP_PACKET_TYPE_VIDEO);
                mediaCodec.releaseOutputBuffer(index, false);
            }
        }
        isLiving = false;
        mediaCodec.stop();
        mediaCodec.release();
        mediaCodec = null;
        virtualDisplay.release();
        virtualDisplay = null;
        mediaProjection.stop();
        mediaProjection = null;
        startTime = 0;
    }

    public void release() {
        isLiving = false;
    }
}
